package com.pig4cloud.common.seate.init;

import cn.hutool.core.lang.Dict;
import com.pig4cloud.common.seate.properties.SeateFileProperties;
import com.pig4cloud.common.seate.properties.SeateRegisterConfigProperties;
import com.pig4cloud.common.seate.properties.SeateRegisterProperties;
import io.seata.common.XID;
import io.seata.common.thread.NamedThreadFactory;
import io.seata.common.util.NetUtil;
import io.seata.core.constants.ConfigurationKeys;
import io.seata.core.rpc.netty.RpcServer;
import io.seata.core.rpc.netty.ShutdownHook;
import io.seata.server.ParameterParser;
import io.seata.server.UUIDGenerator;
import io.seata.server.coordinator.DefaultCoordinator;
import io.seata.server.metrics.MetricsManager;
import io.seata.server.session.SessionHolder;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * seata 程序入口
 */
@Slf4j
@Component
//@Order(0)
public class SeateRunner {

    @Autowired
    private DataSource dataSource;
    @Autowired
    private Environment environment;
    @Autowired
    private SeateFileProperties seateFileProperties;
    @Autowired
    private SeateRegisterProperties seateRegisterProperties;
    @Autowired
    private SeateRegisterConfigProperties seateRegisterConfigProperties;

    public static Dict dict = Dict.create();
    private static ThreadPoolExecutor WORKING_THREADS = new ThreadPoolExecutor(50,
            500, 500, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(20000),
            new NamedThreadFactory("ServerHandlerThread", 500), new ThreadPoolExecutor.CallerRunsPolicy());


    /**
     * 初始化 seata
     *
     * @param args
     */
    @SneakyThrows
    public void run(String... args) {
        dict.set("dataSource", dataSource).set("seateFileProperties", seateFileProperties)
                .set("seateRegisterProperties", seateRegisterProperties).set("seateRegisterConfigProperties", seateRegisterConfigProperties);
        ParameterParser parameterParser = new ParameterParser(args);
        parameterParser.setPort(Integer.parseInt(environment.getProperty("server.port")) - 100);

        //initialize the metrics
        MetricsManager.get().init();

        System.setProperty(ConfigurationKeys.STORE_MODE, parameterParser.getStoreMode());

        RpcServer rpcServer = new RpcServer(WORKING_THREADS);
        //server port
        rpcServer.setListenPort(parameterParser.getPort());
        UUIDGenerator.init(parameterParser.getServerNode());
        //log store mode : file, db
        SessionHolder.init(parameterParser.getStoreMode());

        DefaultCoordinator coordinator = new DefaultCoordinator(rpcServer);
        coordinator.init();
        rpcServer.setHandler(coordinator);
        // register ShutdownHook
        ShutdownHook.getInstance().addDisposable(coordinator);
        ShutdownHook.getInstance().addDisposable(rpcServer);

        //127.0.0.1 and 0.0.0.0 are not valid here.
        if (NetUtil.isValidIp(parameterParser.getHost(), false)) {
            XID.setIpAddress(parameterParser.getHost());
        } else {
            XID.setIpAddress(NetUtil.getLocalIp());
        }
        XID.setPort(8091);

        try {
            log.info("Server addr http://{}:{}", NetUtil.getLocalIp(), rpcServer.getListenPort());
            rpcServer.init();
        } catch (Throwable e) {
            log.error("rpcServer init error:{}", e.getMessage(), e);
            System.exit(-1);
        }

        System.exit(0);
    }

    @SneakyThrows
    public static void main(String[] args) {
        ParameterParser parameterParser = new ParameterParser(args);
//        parameterParser.setPort(Integer.parseInt(environment.getProperty("server.port")) - 100);

        //initialize the metrics
        MetricsManager.get().init();

        System.setProperty(ConfigurationKeys.STORE_MODE, parameterParser.getStoreMode());

        RpcServer rpcServer = new RpcServer(WORKING_THREADS);
        //server port
        rpcServer.setListenPort(parameterParser.getPort());
        UUIDGenerator.init(parameterParser.getServerNode());
        //log store mode : file, db
        SessionHolder.init("db");

        DefaultCoordinator coordinator = new DefaultCoordinator(rpcServer);
        coordinator.init();
        rpcServer.setHandler(coordinator);
        // register ShutdownHook
        ShutdownHook.getInstance().addDisposable(coordinator);
        ShutdownHook.getInstance().addDisposable(rpcServer);

        //127.0.0.1 and 0.0.0.0 are not valid here.
        if (NetUtil.isValidIp(parameterParser.getHost(), false)) {
            XID.setIpAddress(parameterParser.getHost());
        } else {
            XID.setIpAddress(NetUtil.getLocalIp());
        }
        XID.setPort(rpcServer.getListenPort());

        try {
            rpcServer.init();
        } catch (Throwable e) {
            log.error("rpcServer init error:{}", e.getMessage(), e);
            System.exit(-1);
        }

        System.exit(0);
    }
}
